home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / utils / ctv201.arc / CTV201.C < prev   
C/C++ Source or Header  |  1988-03-22  |  20KB  |  865 lines

  1. /*
  2.  * CT:            A file-copying program that maintains time-stamps on the
  3.  *                destination file(s).
  4.  *
  5.  * AUTHOR:        Jonathan Fischer, August 1987 (original)
  6.  *                (see #define VERSION for latest version)
  7.  *
  8.  * USAGE:        ct [-bmnrv] <file1> <file2>
  9.  *        or        ct [-bmnrv] <file1> ... <directory>
  10.  *        where
  11.  *                -b: Backup: only copy files newer than the destination files.
  12.  *                -m: Conserve memory; for MT C-Shell usage.
  13.  *                -n: No information is to be printed.
  14.  *                -r: Recursively copy directories and their contents.
  15.  *                -v: Request user verification when destination file exists.
  16.  *
  17.  * NOTE:        CT now expands wildcards, so it may be called with wildcards
  18.  *                from the desktop.
  19.  *
  20.  *                CT may require some hacking to compile under anything but
  21.  *                Mark Williams C.
  22.  */
  23.  
  24.  
  25.  
  26. #include <stdio.h>
  27. #include <time.h>
  28. #include <ctype.h>
  29. #include <osbind.h>
  30.  
  31.  
  32. #define VERSION            "Version 2.01, Mar. 22, 1988\r\n"
  33. #define YES             1
  34. #define NO                0
  35.  
  36. #define MAXBUFSIZE    500000         /* For Mega machines, make this as big as */
  37.                                 /* you like.  This is typically the most */
  38.                                 /* I'd have free on my ST. */
  39. #define MEMRESERVE    50000        /* Approximate amount of memory that should */
  40.                                 /* be reserved for mallocing. */
  41. #define SMALLBUFSIZE    (40000 + MEMRESERVE)
  42.  
  43. /*
  44.  * Variables used by the wildcard routines:
  45.  * argv gets expanded (if wildcards exist) into newargv.
  46.  */
  47. #define ARGCLIMIT        2000
  48. #define ARGCLIMITSTR    "2000"
  49. int         newargc;
  50. char        *newargv[ARGCLIMIT];/* Allow for (hopefully) much more than */
  51.                                 /* enough space. */
  52.  
  53.  
  54. typedef struct datimbuf {
  55.     unsigned int    seconds:5;
  56.     unsigned int    minutes:6;
  57.     unsigned int    hours:5;
  58.     unsigned int    day:5;
  59.     unsigned int    month:4;
  60.     unsigned int    year:7;
  61. } DATIMBUF;
  62.  
  63. typedef struct {
  64.     char            reserved[21];
  65.     char            attribute;
  66.     DATIMBUF        datime;
  67.     int             losize, hisize;
  68.     char            fname[14];
  69. } DTABUF;
  70.  
  71.  
  72.  
  73. char            *malloc(), *lmalloc(), *rindex(), *strcat(), *strcpy(),
  74.                 *LowerStr();
  75. void            Usage(), Error(), Msg(), GoAway(), Files2Dir(), File2File(), 
  76.                 FindWildcards(), ExpandWildcards(), CopyDir(), ReadRoot();
  77.  
  78. DATIMBUF        finfo;
  79. DTABUF            dta;
  80.  
  81. long            _stksize = 15000L;        /* Override default 2K stack. */
  82. unsigned long    bufsize;
  83.  
  84. int             firstarg;        /* First argument (after options). */
  85. int             ch;             /* Character read from keyboard. */
  86.  
  87. char            *buf;            /* I/O buffer. */
  88. char            *prgname;        /* Program name for error messages. */
  89. char            tempbuf[256];
  90. char            FromDesktop,
  91.                 info, verify, recurse, memconserve, backup; /* Flags */
  92.  
  93.  
  94.  
  95.  
  96.  
  97.  
  98. int
  99. main(argc, argv)
  100.     int     argc;
  101.     char    **argv;
  102. {
  103.     register int    loop;
  104.  
  105.  
  106.     /*
  107.      * Most shells pass the program name in argv[0].  But if argv[0] is
  108.      * empty, then set the program name to "ct."
  109.      */
  110.     if (*(prgname = argv[0]) == 0) {
  111.         prgname = "ct";
  112.         /* Assume that ct is being run from the desktop. */
  113.         FromDesktop = YES;
  114.     } /* if */
  115.     else
  116.         FromDesktop = NO;
  117.  
  118.  
  119.     if (argc < 3) {
  120.         Usage();
  121.     } /* if one or no params */
  122.  
  123.  
  124.  
  125.  
  126.     /*
  127.      * Set GEMDOS' dta buffer.
  128.      */
  129.     Fsetdta(&dta);
  130.  
  131.  
  132.     FindWildcards(&argc, &argv);
  133.  
  134.  
  135.     /* Get any command line options (e.g., "-v"). */
  136.     backup = NO;
  137.     memconserve = NO;
  138.     info = YES;
  139.     recurse = NO;
  140.     verify = NO;
  141.  
  142.     if (argv[1][0] == '-') {
  143.         firstarg = 2;
  144.  
  145.         for (loop = YES; argv[1][loop]; ++loop) {
  146.             switch (argv[1][loop]) {
  147.                 case 'b':
  148.                     backup = YES;
  149.                     break;
  150.                 case 'm':
  151.                     memconserve = YES;
  152.                     break;
  153.                 case 'n':
  154.                     info = NO;
  155.                     break;
  156.                 case 'r':
  157.                     recurse = YES;
  158.                     break;
  159.                 case 'v':
  160.                     verify = YES;
  161.                     break;
  162.                 default:
  163.                     Usage();
  164.             } /* switch */
  165.         } /* for */
  166.     } /* if */
  167.     else
  168.         firstarg = 1;
  169.  
  170.  
  171.     /* Check for only one file parameter. */
  172.     if (argc - firstarg == 1)
  173.         Usage();
  174.  
  175.  
  176.     /*
  177.      * If memconserve:
  178.      *      Allocate a maximum of SMALLBUFSIZE bytes.
  179.      *
  180.      * else:
  181.      *      Allocate the largest buffer possible.
  182.      */
  183.     bufsize = memconserve ? SMALLBUFSIZE : MAXBUFSIZE;
  184.  
  185.     while (((buf = lmalloc(bufsize)) == NULL) &&
  186.         (bufsize -= 2000) > 0)
  187.         ;
  188.     if (buf == NULL)
  189.         Error("Out of memory.", NULL);
  190.  
  191.     /*
  192.      * Now free the buffer and reallocate one of a size which leaves enough
  193.      * room for all the mallocs later in the program.  NOTE: this all could
  194.      * have been done with a Malloc(-1L), but mixing Malloc and malloc seems
  195.      * to be a definite no-no, and I prefer to use malloc over Malloc.
  196.      */
  197.     free(buf);
  198.     buf = lmalloc(bufsize -= MEMRESERVE);
  199.  
  200.  
  201.     /*
  202.      * Format I:
  203.      *        Backup one or more files to a destination directory.
  204.      */
  205.     if (IsDir(argv[argc-1]))
  206.         Files2Dir(argc, argv);
  207.  
  208.  
  209.     /*
  210.      * Format II:
  211.      *        Copy one file to another.
  212.      */
  213.     else if (argc - firstarg == 2)
  214.         File2File(argv[firstarg], argv[firstarg+1]);
  215.     else
  216.         Error(argv[argc-1], " is not a directory.");
  217.  
  218.     GoAway(0);
  219. } /* main() */
  220.  
  221.  
  222.  
  223. void
  224. Usage()
  225. {
  226.     Cconws("Usage:\t");
  227.     Cconws(prgname);
  228.     Cconws(" [-bmnrv] <file1> <file2>\r\n\t");
  229.     Cconws(prgname);
  230.     Cconws(" [-bmnrv] <file> ... <directory>\r\n\n\
  231. \t-b: Backup: only copy files newer than the destination files.\r\n\
  232. \t-m: Conserve memory (for MT C-Shell).\r\n");
  233.     Cconws("\t-n: No information is to be printed.\r\n\
  234. \t-r: Recursively copy directories and their contents.\r\n\
  235. \t-v: Request user verification when destination file exists.\r\n");
  236.     Cconws(VERSION);
  237.  
  238.     GoAway(1);
  239. } /* Usage() */
  240.  
  241.  
  242.  
  243. void
  244. Error(string1, string2)
  245.     char    *string1, *string2;
  246. {
  247.     Cconws(prgname);
  248.     Cconws(":\t");
  249.     Cconws(string1);
  250.     if (string2 != NULL)
  251.         Cconws(string2);
  252.     Cconws("\r\n");
  253.  
  254.     GoAway(1);
  255. } /* Error() */
  256.  
  257.  
  258.  
  259. void
  260. Msg(string1, string2)
  261.     char    *string1, *string2;
  262. {
  263.     Cconws(prgname);
  264.     Cconws(":\t");
  265.     Cconws(string1);
  266.     if (string2 != NULL)
  267.         Cconws(string2);
  268.     Cconws("\r\n");
  269. } /* Msg() */
  270.  
  271.  
  272.  
  273. void
  274. GoAway(code)
  275.     int     code;
  276. {
  277.     if (FromDesktop) {
  278.         Cconws("\r\nHit any key to return to desktop...");
  279.         Cnecin();
  280.         Cconws("\033f");
  281.     } /* if */
  282.  
  283.     exit(code);
  284. } /* GoAway() */
  285.  
  286.  
  287.  
  288.  
  289.  
  290. void
  291. File2File(source, dest)
  292.     char    *source, *dest;
  293. {
  294.     unsigned long    rcount;
  295.     char            retry_open;
  296.     int             sfile, dfile;
  297.  
  298.  
  299.  
  300.     retry_open = YES;
  301.  
  302.     /* Open the files. */
  303. retry:
  304.     if ((sfile = Fopen(source, 0)) < 0) {
  305.         if (IsDir(source)) {
  306.             if (recurse) {
  307.                 CopyDir(source, dest);
  308.                 return;
  309.             } /* if */
  310.             else {
  311.                 Msg(source, " is a directory.");
  312.                 return;
  313.             } /* else */
  314.         } /* if */
  315.  
  316.         /*
  317.          * If a disk has been swapped, GEMDOS doesn't know about any
  318.          * files contained in subdirectories.  So in case this is the problem,
  319.          * get GEMDOS to read the root directory of the disk in question.
  320.          * Then it will know about subdirectories on the new disk.
  321.          */
  322.         else if (retry_open) {
  323.             retry_open = NO;        /* Only want to retry once. */
  324.  
  325.             ReadRoot(source);
  326.             goto retry;
  327.         } /* if */
  328.  
  329.         Msg("Can't open ", source);
  330.         return;
  331.     } /* if can't open file. */
  332.  
  333.  
  334.  
  335.     /*
  336.      * If "-b" is specified, check if the file exists, and if it does
  337.      * then only copy over it if the source file is more recent.
  338.      *
  339.      * If the "-v" option has been specified, then first check if
  340.      * the destination file already exists.  If so, query whether
  341.      * or not to replace it.
  342.      */
  343.     if ((verify || backup) && Fsfirst(dest, 0x23) == 0) {
  344.         if (backup) {
  345.             /* Store the destination timestamp in 'finfo.' */
  346.             finfo = dta.datime;     /* Structure assignment. */
  347.             Fsfirst(source, 0x23);    /* Get info for source file. */
  348.  
  349.             /* 
  350.              * Compare timestamps of source and dest.  If the source isn't
  351.              * more recent than the dest, then return.
  352.              */
  353.             if (!MoreRecent(dta.datime, finfo))
  354.                 return;
  355.         } /* if */
  356.  
  357.         if (verify)
  358.             while (1) {
  359.                 Cconws("Replace file \"");
  360.                 Cconws(dest);
  361.                 Cconws("\"? (Yes/No/All) ");
  362.  
  363.                 ch = tolower((int)Cnecin());
  364.                 Cconws("\r\033K");
  365.  
  366.                 if (ch == 'y')
  367.                     break;
  368.                 if (ch == 'n')
  369.                     return;
  370.                 if (ch == 'a') {
  371.                     verify = NO;
  372.                     break;
  373.                 } /* if */
  374.             } /* while and if*/
  375.     } /* if */
  376.  
  377.  
  378.     /* Open the destination file. */
  379.     if ((dfile = Fcreate(dest, 0)) < 0) {
  380.         Fclose(sfile);
  381.  
  382.         if (IsDir(dest)) {
  383.             Msg(dest, " exists and is a directory.");